import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;

import  javax.swing.JOptionPane;
import javax.swing.JFrame;

/**

 * @author Andy
 */

@SuppressWarnings("serial")
public class Game extends JFrame implements KeyListener {

        private static final int BLOCKSIZE = 60;
		private GraphicsDevice device;
        private BufferStrategy stratagy;
        private Map map;
        private EntityManager manager;
        private ComponentCollection components;
        private Canvas drawCanvas;
        private int normalFps = 60;
        private FpsCounter count;
        Player player;
        Block blk;
       
       
        public Game()
        {      
                super("BomberBoys");
                setSize(512, 512); //set default size
                this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                drawCanvas = new Canvas();
                this.add(drawCanvas);
               
                components = new ComponentCollection();
                drawCanvas.addKeyListener(this);
                map = new Map();
                map.createMap(47, 30);
                manager = new EntityManager();
                populateMap();
               
                components.addComponent(map);
                components.addComponent(manager);
                count = new FpsCounter();
                components.addComponent(count);
                boolean success = initGraphics();
               
                if(!success)
                  JOptionPane.showInputDialog(
                                   "Error with hardware acceleration" +
                                   "See consoles for details");
                 
       
                this.setIgnoreRepaint(true);
        }
       
        private void populateMap()
        {
                player = new Player(60, 60);
   
                manager.addEntity(player);
                drawBlocks("src/test.txt");
    
        }
       
        private void drawBlocks(String fileName) {

        	System.out.println("Trying to draw blocks");
        	int x = 0, y = 0;
        	try {
        		FileInputStream fstream = new FileInputStream(fileName);

        		DataInputStream in = new DataInputStream(fstream);
        		BufferedReader br = new BufferedReader(new InputStreamReader(in));
        		int theChar;
        		char myChar;

        		while ((theChar = br.read()) != -1) {
        			myChar = (char) theChar;

        			Block blk;

        			if (myChar == 'x') {
        				blk = new Block(true, (x * BLOCKSIZE), (y * BLOCKSIZE));
        				manager.addEntity(blk);
        				System.out.println("this block was drawn: breakable at " + x + " " + y);
        				x++;

        			} 
        			else if (myChar == '1') {
        				blk = new Block(false, (x * BLOCKSIZE), (y * BLOCKSIZE));
        				manager.addEntity(blk);
        				System.out.println("this block was drawn: unbreakable at " + x + " " + y);
        				x++;
        			} 
        			else if (myChar == '0') {
        				x++;
        				System.out.println("Empty space! at " + x + " " + y);
        			}
        			else if(myChar == ';') {
        				y++;
        				x = 0;
        				System.out.println("end of row! at " + x + " " + y);
        			}
        			else
        				System.out.println("Error with map file!!");


        		}

        		in.close();
        	}catch (Exception e){
        		System.err.println("Error: " + e.getMessage());
        	}
        }
        private boolean initGraphics()
        {
                setVisible(true);//the frame must be visible to create buffer strategy
               
                try {
                drawCanvas.createBufferStrategy(3);
                stratagy = drawCanvas.getBufferStrategy();
                GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
                device = ge.getDefaultScreenDevice();
               
                }
                catch(Exception ex){
                        System.out.println(ex.toString());
                   return false;
                }
                setIgnoreRepaint(true);
               
               
                return true;
        }
        /**
         * Called once per frame
         */
        public void render()
        {
                float dt = 1;
                if(count.currentFps != 0)
                        dt = normalFps/(float)count.currentFps;
                components.update(dt);
               
                        Graphics2D g = (Graphics2D)this.getGraphics();
                        try{
                                if(stratagy != null)
                                        g = (Graphics2D)stratagy.getDrawGraphics();
                                System.out.println(g);
                                g.fillRect(0, 0, getWidth(), getHeight());
                                g.setColor(Color.BLACK);
                               
                                components.render(g);
                        }
                        finally{
                                if(g != null)
                                        g.dispose();
                        }

                if(stratagy != null &&
                   !stratagy.contentsLost())
                        stratagy.show();
               
                Toolkit.getDefaultToolkit().sync();//i have heard this is something that should be done for linux systems
        }
       
        /**
         * Tells the window to go full screen if able
         */
        public boolean setFullScreen(boolean full)
        {
                if(device == null)
                        return false;
                boolean success = false;
                setVisible(false);
                dispose(); //we must dispose resources (and recreate) resources to go full screen
               
                if(device.isFullScreenSupported() && full){
                        setUndecorated(true); //remove window border
                        device.setFullScreenWindow(this);
                        this.requestFocus(); //sometimes it could be full screen and not focused
                        success = true;
                }
                else {
                        setUndecorated(false);
                        device.setFullScreenWindow(null);
                }
                setVisible(true);
       
                return success;
        }
        /**
         * Returns all display modes compatible on current system.
         */
        public DisplayMode[] getDisplayModes()
        {
                return device.getDisplayModes();
        }
       
        /**
         * Sets a new display mode thats compatable with system
         * @param newMode new mode to change to. This mode must be one of the modes from getDisplayModes.
         * @return returns true if it successfully switched display modes false otherwise.
         */
        public boolean setDisplayMode(DisplayMode newMode)
        {
                try{
                        device.setDisplayMode(newMode);
                }catch(IllegalArgumentException ex) { return false;}
                return true;
        }

        @Override
        public void keyPressed(KeyEvent e)
        {
                if(e.getKeyCode() == KeyEvent.VK_ESCAPE)
                        dispose(); //if this is the last window it sould terminate the program

               
                switch(e.getKeyCode())
                {
                        case KeyEvent.VK_A: player.move(Player.Direction.Left); break;
                        case KeyEvent.VK_W: player.move(Player.Direction.Up); break;
                        case KeyEvent.VK_D: player.move(Player.Direction.Right); break;
                        case KeyEvent.VK_S: player.move(Player.Direction.Down); break;
                }
                //e.consume();
        }

        @Override
        public void keyReleased(KeyEvent e)
        {
                switch(e.getKeyCode())
                {
                        case KeyEvent.VK_A:
                        case KeyEvent.VK_W:
                        case KeyEvent.VK_D:
                        case KeyEvent.VK_S:
                                player.stop();
                        break;
                }
                if(e.getKeyCode() == KeyEvent.VK_SPACE)
                    player.dropBomb();

        }


        @Override
        public void keyTyped(KeyEvent e) {}
       
        public static void main(String[] args)
        {
                Game game = new Game();
                game.setFullScreen(true);
                //game.setDisplayMode(game.getDisplayModes()[0]);
                while(game.isVisible())
                        game.render();  
        }
}

